package pruebas;

import java.util.*;

import modelo.*;
import modelo.estrategias.*;
import modelo.moviles.exceptions.MovilNoEstaEnLaLista;
import modelo.moviles.*;
import modelo.moviles.balas.Bala;
import modelo.moviles.balas.BalaLaser;
import modelo.moviles.naves.Algo42;
import modelo.moviles.naves.AvionCivil;
import modelo.moviles.naves.Avioneta;
import modelo.moviles.naves.Caza;
import modelo.moviles.naves.Explorador;
import modelo.moviles.naves.Nave;
import junit.framework.TestCase;

public class TestNivel extends TestCase{

	/* "testea el Nivel" */
	public void testNivel() {
		
		/*"Creo el nivel" */
		Nivel nivel = new Nivel(10,12);
	
		/*"Al iniciar el nivel el puntaje es 0" */
		assertEquals("El constructor no esta iniciando el puntaje",nivel.getPuntaje(), 0);
	
		/*"La cantidad de Columnas debe ser 12" */
		assertEquals("El constructor no esta iniciando las columnas",nivel.getCantColumnas(), 12);
	
		/*"La cantidad de Filas debe ser 10" */
		assertEquals("El constructor no esta iniciando las filas",nivel.getCantFilas(),10);
	
		/*"Como la lista de moviles esta vacia, al intentar remover uno debe dar error." */
		Nave movil = new Explorador (new Nivel(1,1));
		try{
			nivel.removerMovil(movil);
			fail("Removio un movil que no estaba en la lista.");
		} catch(MovilNoEstaEnLaLista e){
		}
	
		nivel.agregarMovil(movil);
		
		/*"Ahora que tiene movil debe poder removerlo" */
		try{
			nivel.removerMovil(movil);
		} catch(MovilNoEstaEnLaLista e){
			fail(e.getDetalle());
		}

		/*"Le marco el nivel al Movil para que lo agregue a la lista luego lo vuelvo a sacar para probar que lo agrego." */
		movil.setNivel(nivel);
		try{
			nivel.removerMovil(movil);
		} catch(MovilNoEstaEnLaLista e){
		}
	
		/*"Le marco el nivel al Movil y le pido que se destrulla, 
		 * asi el nivel lo saca de la lista y sumamos el puntaje al Puntaje del nivel" */
		movil.setNivel(nivel);
		movil.destruirse();
	
		/*"Los Exploradores Tienen un puntaje de 50, 
		 * el puntaje debe haberse incrementado." */
		assertEquals("no esta sumando el puntaje.",nivel.getPuntaje(),50);
	
		/*"Todavia no consiguio los 1000 puntos. el metodo consiguioPunajeNecesario debe dar false." */
		assertFalse("No chequea bien si consiguio el puntaje necesario",nivel.consiguioPuntajeNecesario());
	
		/*"Agrego y destruyo 19 Exploradores mas para poder conseguir el puntaje necesario y pruebo" */
		for (int i =1 ; i < 20 ; i++){
			movil.setNivel(nivel);
			movil.destruirse();
		}
		assertTrue("No consiguio el puntaje necesario cuando debia", nivel.consiguioPuntajeNecesario());
	}
 
	public void testProcesarCasilleroCompartido(){
		
		/*"Creo el nivel" */
		Nivel nivel = new Nivel(10,12);
	
		/*"Probamos el encuentro entre 2 moviles - 1 bala de Algo42 y 1 AvionCivil   - Deben estallar los 2" */
		Bala origen = new BalaLaser(nivel);
		origen.setEstrategia(new EstrategiaBalaAlgo42());
		origen.setEnemiga(false);
		Movil destino = new AvionCivil(nivel);
	
		Stack<Movil> pila = new Stack<Movil>();
		pila.push(origen);
		pila.push(destino);
	
		nivel.procesarCasilleroCompartido(pila);
	
		assertFalse("'El origen debia estallar y no estallo 1.",origen.noEstallo());
		assertFalse("'El destino debia estallar y no estallo 1.",destino.noEstallo());
	
		assertEquals("No se sumo el puntaje",nivel.getPuntaje(), -300);
	
		/*"Probamos el encuentro entre 2 moviles - 1 bala de Algo42 y 1 Caza - Debe estallar la bala" */
	
		origen = new BalaLaser(nivel);
		origen.setEstrategia(new EstrategiaBalaAlgo42());
		origen.setEnemiga(false);
	
		destino = new Caza(nivel);
	
		pila = new Stack<Movil>();
		pila.push(origen);
		pila.push(destino);
	
		nivel.procesarCasilleroCompartido(pila);
		
		assertFalse("'El origen debia estallar y no estallo 2.",origen.noEstallo());
		assertTrue("'El destino no debia estallar y estallo 2.",destino.noEstallo());
		
		/*"Probamos el encuentro entre 2 moviles - 1 bala de Algo42 y 1 BalaLaser - Deben estallar las dos" */
		origen = new BalaLaser(nivel);
		origen.setEstrategia(new EstrategiaBalaAlgo42());
		origen.setEnemiga(false);
	
		Bala destino2 = new BalaLaser(nivel);
		destino2.setEstrategia(new EstrategiaLineaRecta());
		destino2.setEnemiga(true);
		
		pila = new Stack<Movil>();
		pila.push(origen);
		pila.push(destino2);
	
		nivel.procesarCasilleroCompartido(pila);
		
		assertFalse("'El destino debia estallar y no estallo 3.",destino2.noEstallo());
		assertFalse("'El origen debia estallar y no estallo 3.",origen.noEstallo());
		
		/*"Probamos el encuentro entre 2 origenes - 1 Explorador y 1 Caza - No debe estallar ninguno" */
		Movil origen2 = new Explorador(nivel);
		destino = new Caza(nivel);
	
		pila = new Stack<Movil>();
		pila.push(origen2);
		pila.push(destino);
	
		nivel.procesarCasilleroCompartido(pila);
		
		assertTrue("'El origen no debia estallar y estallo 4.",origen2.noEstallo());
		assertTrue("'El destino no debia estallar y estallo 4.",destino.noEstallo());
		
		/*"Probamos el encuentro entre 2 origenes - 1 Explorador y 1 BalaLaser - No debe estallar ninguno" */
		origen2 = new Explorador(nivel);
		destino = new BalaLaser(nivel);
		destino.setEstrategia(new EstrategiaLineaRecta());

		pila = new Stack<Movil>();
		pila.push(origen2);
		pila.push(destino);
	
		nivel.procesarCasilleroCompartido(pila);
		
		assertTrue("'El origen no debia estallar y estallo 5.",origen2.noEstallo());
		assertTrue("'El destino no debia estallar y estallo 5.",destino.noEstallo());
	
		/*"Probamos el encuentro entre 2 origenes - 1  AvionCivil y 1 bala de Algo42 - Deben estallar los 2" */
		destino = new AvionCivil(nivel);
		origen = new BalaLaser(nivel);
		origen.setEstrategia(new EstrategiaBalaAlgo42());
		origen.setEnemiga(false);
		
		pila = new Stack<Movil>();
		pila.push(destino);
		pila.push(origen);
	
		nivel.procesarCasilleroCompartido(pila);
		
		assertFalse("'El destino no debia estallar y estallo 6.",origen.noEstallo());
		assertFalse("'El origen no debia estallar y estallo 6.",destino.noEstallo());
	}
	
	public void testProcesarCasilleros(){
		
		/*"Creo el nivel" */
		Nivel nivel = new Nivel(30,30);
	
		/*"Probamos el encuentro entre 2 moviles - 1 bala de Algo42 y 1 AvionCivil   - Deben estallar los 2" */
		Bala origen = new BalaLaser(nivel);
		origen.setEstrategia(new EstrategiaBalaAlgo42());
		origen.setPosicion(new Posicion(20,20));
		origen.setEnemiga(false);
		Nave destino = new AvionCivil(nivel);
		destino.setPosicion(new Posicion(20,20));
	
		nivel.procesarEncuentros();
		
		assertFalse("El origen debia estallar y no estallo 1.",origen.noEstallo());
		assertFalse("El destino debia estallar y no estallo 1.",destino.noEstallo());
		assertEquals("No se sumo el puntaje 1",nivel.getPuntaje(), -300);
		
		/*"Mismos  moviles - 1 bala de Algo42 y 1 AvionCivil  pero en casilleros distintos  - No deben estallar " */
		
		origen = new BalaLaser(nivel);
		origen.setEstrategia(new EstrategiaBalaAlgo42());
		origen.setPosicion(new Posicion(20,20));
		origen.setEnemiga(false);
		destino = new AvionCivil(nivel);
		destino.setPosicion(new Posicion(40,20));
	
		nivel.procesarEncuentros();
	
		assertTrue("El origen no debia estallar y estallo 2.",origen.noEstallo());
		assertTrue("El destino no debia estallar y estallo 2.",destino.noEstallo());
		
			
		/*"Creo el nivel" */
		nivel = new Nivel(3,3);
	
		/*"Probamos el encuentro entre 2 moviles - 1 Algo42 y 1 BalaLaser  - La bala debe estallar" */
		origen = new BalaLaser(nivel);
		origen.setEstrategia(new EstrategiaLineaRecta());
		origen.setPosicion(new Posicion(10,20));
		origen.setEnemiga(true);
		destino = new Algo42(nivel);
		destino.setPosicion(new Posicion(10,20));
	nivel.procesarEncuentros();
		
		assertEquals("La bala no le pego al Algo42 3.",destino.getEnergia().getPorcentaje(), 70);
		assertTrue("El destino no debia estallar y estallo 3.",destino.noEstallo());
		assertFalse("El origen debia estallar y no estallo 3",origen.noEstallo());
	
		
		/*"Al mismo tiempo se encuentran 2 moviles - 1 bala de Algo42 y 1 AvionCivil   - Deben estallar los 2" */
		Bala destino2 = new BalaLaser(nivel);
		destino2.setEstrategia(new EstrategiaBalaAlgo42());
		destino2.setPosicion(new Posicion(20,50));
		destino2.setEnemiga(false);
	
		Movil origen2 = new AvionCivil(nivel);
		origen2.setPosicion(new Posicion(20,50));
	
		assertTrue("El destino2 no debia estallar y estallo 3.",destino2.noEstallo());
		assertTrue("El origen2 no debia estallar y estallo 3.",origen2.noEstallo());
		
	}
	

	/*"Testo todo el comportamiento relativo a las flotas del nivel" */
	public void testProcesandoFlotas(){
		
		Flota flota = new Flota ();
	
		Nivel nivel = new Nivel(30, 30);
		nivel.agregarFlota(flota);
	
		/*"Agregamos una nave que no es guia a la flota." */
		Nave nave1 = new Avioneta(nivel);
		flota.agregarNave(nave1);
	
		/*"Agregamos una nave guia a la flota." */
		Nave nave2 = new Avioneta(nivel);
		nave2.setGuia(true);
		flota.agregarNave(nave2);
	
		/*"Actualizo las flotas del nivel. Como la flota tiene una nave guia no debe huir" */
		nivel.actualizarFlotas();
		assertFalse("La flota debe huir teniendo guia",flota.debeHuir());
	
		/*"Mato al guia." */
		nave2.estallar();
	
		/*"Actualizo las flotas del nivel. 
		 * Como no tiene una nave guia la flota debe huir" */
		nivel.actualizarFlotas();
	
		/*"Como no tiene una nave guia la flota debe huir" */
		assertTrue("La flota no debe huir sin tener guia",flota.debeHuir());
	
		/*"Luego de huir la nave que queda en la flota no debe poder disparar." */
		assertFalse("La nave puede disparar huyendo",nave1.debeDisparar());	
	
		/*"Creo un nuevo nivel" */
		nivel = new Nivel(100,100);
	
		/*"Creo una flota en el nivel" */
		nivel.crearFlota();	
		assertFalse("La flota no se creo.",nivel.getFlotas().isEmpty());
	
		/*"Actualizo el estado de las flotas, como nada cambio debe seguir teniendo valores." */
		nivel.actualizarFlotas();
		assertFalse("La flota se actualizo mal.",nivel.getFlotas().isEmpty());
	
		/*"Mato al guia de la flota" */ 
		Iterator<Flota> it = nivel.getFlotas().iterator();
		Flota flotaActual;
		while (it.hasNext()){
			flotaActual = it.next();
			Nave naveActual;
			Iterator<Nave> itNave = flotaActual.getFlota().iterator();
			while (itNave.hasNext()){
				naveActual = itNave.next();
				if (naveActual.esGuia()){
					naveActual.destruirse();
					nave1 = naveActual;
				}
			}
		}

		assertTrue("la nave no es guia",nave1.esGuia());
		assertFalse("la nave no estallo",nave1.noEstallo());
		assertEquals("El nivel no sumo el puntaje",nivel.getPuntaje(),nave1.getPuntaje());
	}

}

